package com.navinfo.tripanalysis.common.arithmetic.manager;

import com.navinfo.tripanalysis.common.arithmetic.common.CommonData;
import com.navinfo.tripanalysis.common.arithmetic.common.DrivingData;
import com.navinfo.tripanalysis.common.arithmetic.common.OuterEventData;
import com.navinfo.tripanalysis.common.arithmetic.convert.EventDataConvert;
import com.navinfo.tripanalysis.common.arithmetic.convert.EventDataToVarData;
import com.navinfo.tripanalysis.common.arithmetic.enums.EventStatus;
import com.navinfo.tripanalysis.common.arithmetic.enums.EventType;
import com.navinfo.tripanalysis.common.arithmetic.logger.ArithmeticLogger;
import com.navinfo.tripanalysis.common.arithmetic.logger.ArithmeticLoggerFactory;
import com.navinfo.tripanalysis.common.util.Constant;
import com.navinfo.tripanalysis.common.vehicle.VehicleInfo;

import java.lang.reflect.ParameterizedType;
import java.util.Optional;
import java.util.function.BiConsumer;

/**
 * 抽象算法，提供数据注入.
 * @author 水哥
 */
public abstract class AbstractArithmetic<Var> implements IArithmetic {
    protected  final ArithmeticLogger logger = ArithmeticLoggerFactory.getLogger(getClass());
    /**
     * 车辆id.
     */
    protected Long terminalId;
    /**
     * 中间缓存对象
     */
    protected DrivingData drivingData;
    /**
     * 是否输出事件
     */
    private boolean outputEvent = true;

    @Override
    public IArithmetic init(DrivingData drivingData) {
        this.drivingData = drivingData;
        this.terminalId = drivingData.getCommonData().getTid();
        logger.setTerminalId(terminalId);
        return this;
    }

    /**
     * 是否输出事件
     * @return
     */
    protected boolean isOutputEvent() {
        if(!outputEvent) {
            return false;
        }

        boolean upload0F37 = false;
        VehicleInfo vehicleInfo = this.drivingData.getVehicleInfo();
        if(vehicleInfo != null){
            upload0F37 = vehicleInfo.isUpload0F37();
        }
        return ((upload0F37 && Constant.PROTO_0F37.equals(this.drivingData.getProtocol())))||
                ((!upload0F37 && Constant.PROTO_0200.equals(this.drivingData.getProtocol())));
    }

    public AbstractArithmetic setOutputEvent(boolean outputEvent) {
        this.outputEvent = outputEvent;
        return this;
    }

    /**
     * 获取中间变量中具体算法的统计缓存
     * @return Var
     */
    protected Var getObj() {
        return (Var) this.drivingData.getOrCreateStatisticData(this.getClass().getSimpleName(),
                (Class<Var>) (((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]));
    }

    /**
     * 设置中间变量中具体算法的统计缓存
     * @param obj 当前算法对应泛型对象
     */
    protected void setObj(Var obj) {
        this.drivingData.setStatisticData(this.getClass().getSimpleName(), obj);
    }

    /**
     * 获取中间变量中的公共缓存
     * @return CommonData
     */
    protected CommonData getCommonData() {
        return drivingData.getCommonData();
    }

    /**
     * 获取当前事件状态的通用方法.
     * @param pre     前一个节点
     * @param current 当前节点
     * @return EventStatus
     */
    public EventStatus getEventStatus(boolean pre, boolean current) {
        if (pre && current) {
            return EventStatus.IN;
        }
        if (pre) {
            return EventStatus.END;
        }
        if (current) {
            return EventStatus.START;
        }
        return EventStatus.OUT;
    }

    /**
     * 通用的事件开始处理，放入正在进行中事件缓存中
     * @param eventType
     */
    protected OuterEventData startEventData(EventType eventType) {
        OuterEventData eventData = EventDataConvert.newInstanceAndConvertStart(drivingData);
        eventData.setEvent(eventType);
        drivingData.putEventData(eventData);
        return eventData;
    }
    /**
     * 通用的累加事件的里程、油耗
     */
    protected void calcEventData(EventType eventType) {
        Optional.ofNullable(drivingData.getEventData(eventType)).ifPresent(eventData -> {
            EventDataConvert.convertCommonExtendField(eventData, drivingData);
        });
    }

    /**
     * 结束事件，加入事件输出列表，删除事件缓存
     */
    protected void endEventData(EventType eventType) {
        Optional.ofNullable(drivingData.getEventData(eventType)).ifPresent(eventData -> {
            EventDataConvert.convertEnd(eventData, drivingData);

            //放入输出事件列表
            drivingData.addEventDataToList(eventData);

            //删除当前缓存
            drivingData.removeEventData(eventType);
        });
    }

    /**
     * 结束事件，赋值到统计数据中，加入事件输出列表，删除事件缓存
     * @param eventType
     * @param toVar 累加事件数据到统计数据中
     */
    protected void endEventData(EventType eventType, EventDataToVarData toVar) {
        Optional.ofNullable(drivingData.getEventData(eventType)).ifPresent(eventData -> {
            EventDataConvert.convertEnd(eventData, drivingData);

            //累加事件数据到统计数据中
            toVar.accumulate(eventData);

            //放入输出事件列表
            drivingData.addEventDataToList(eventData);

            //删除当前缓存
            drivingData.removeEventData(eventType);
        });
    }

    /**
     * 结束事件，执行事件处理器，删除事件缓存
     * @param eventType
     * @param consumer 事件处理器
     */
    protected void endEventData(EventType eventType, BiConsumer<OuterEventData, DrivingData> consumer) {
        Optional.ofNullable(drivingData.getEventData(eventType)).ifPresent(eventData -> {
            EventDataConvert.convertEnd(eventData, drivingData);

            //累加事件数据到统计数据中
            consumer.accept(eventData, drivingData);

            //删除当前缓存
            drivingData.removeEventData(eventType);
        });
    }

}
